#include <fstream>
#include <iostream>
#include <list>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
/* TODO:
 * 宏定义
 * 跑通日志模块
 * 细节完善
 */

// 宏定义
// 日志内容去哪儿了 ？？？
// 流式风格与C风格宏？
#define SYLAR_LOG_LEVEL(logger, level)                                        \
  if (level <= logger->getLevel())                                            \
  sylar::LogEventWrap(logger,                                                 \
                      sylar::LogEvent::ptr(new sylar::LogEvent(               \
                          logger->getName(), level, __FILE__, __LINE__,       \
                          sylar::GetElapsedMS() - logger->getCreateTime(),    \
                          sylar::GetThreadId(), sylar::GetFiberId(), time(0), \
                          sylar::GetThreadName())))                           \
      .getLogEvent()                                                          \
      ->getSS()

#define SYLAR_LOG_FATAL(logger) SYLAR_LOG_LEVEL(logger, sylar::LogLevel::FATAL)

#define SYLAR_LOG_ALERT(logger) SYLAR_LOG_LEVEL(logger, sylar::LogLevel::ALERT)

#define SYLAR_LOG_CRIT(logger) SYLAR_LOG_LEVEL(logger, sylar::LogLevel::CRIT)

#define SYLAR_LOG_ERROR(logger) SYLAR_LOG_LEVEL(logger, sylar::LogLevel::ERROR)

#define SYLAR_LOG_WARN(logger) SYLAR_LOG_LEVEL(logger, sylar::LogLevel::WARN)

#define SYLAR_LOG_NOTICE(logger) \
  SYLAR_LOG_LEVEL(logger, sylar::LogLevel::NOTICE)

#define SYLAR_LOG_INFO(logger) SYLAR_LOG_LEVEL(logger, sylar::LogLevel::INFO)

#define SYLAR_LOG_DEBUG(logger) SYLAR_LOG_LEVEL(logger, sylar::LogLevel::DEBUG)

/**
 * @brief 使用C printf方式将日志级别level的日志写入到logger
 * @details
 * 构造一个LogEventWrap对象，包裹包含日志器和日志事件，在对象析构时调用日志器写日志事件
 * @todo 协程id未实现，暂时写0
 */
#define SYLAR_LOG_FMT_LEVEL(logger, level, fmt, ...)                          \
  if (level <= logger->getLevel())                                            \
  sylar::LogEventWrap(logger,                                                 \
                      sylar::LogEvent::ptr(new sylar::LogEvent(               \
                          logger->getName(), level, __FILE__, __LINE__,       \
                          sylar::GetElapsedMS() - logger->getCreateTime(),    \
                          sylar::GetThreadId(), sylar::GetFiberId(), time(0), \
                          sylar::GetThreadName())))                           \
      .getLogEvent()                                                          \
      ->printf(fmt, __VA_ARGS__)

#define SYLAR_LOG_FMT_FATAL(logger, fmt, ...) \
  SYLAR_LOG_FMT_LEVEL(logger, sylar::LogLevel::FATAL, fmt, __VA_ARGS__)

#define SYLAR_LOG_FMT_ALERT(logger, fmt, ...) \
  SYLAR_LOG_FMT_LEVEL(logger, sylar::LogLevel::ALERT, fmt, __VA_ARGS__)

#define SYLAR_LOG_FMT_CRIT(logger, fmt, ...) \
  SYLAR_LOG_FMT_LEVEL(logger, sylar::LogLevel::CRIT, fmt, __VA_ARGS__)

#define SYLAR_LOG_FMT_ERROR(logger, fmt, ...) \
  SYLAR_LOG_FMT_LEVEL(logger, sylar::LogLevel::ERROR, fmt, __VA_ARGS__)

#define SYLAR_LOG_FMT_WARN(logger, fmt, ...) \
  SYLAR_LOG_FMT_LEVEL(logger, sylar::LogLevel::WARN, fmt, __VA_ARGS__)

#define SYLAR_LOG_FMT_NOTICE(logger, fmt, ...) \
  SYLAR_LOG_FMT_LEVEL(logger, sylar::LogLevel::NOTICE, fmt, __VA_ARGS__)

#define SYLAR_LOG_FMT_INFO(logger, fmt, ...) \
  SYLAR_LOG_FMT_LEVEL(logger, sylar::LogLevel::INFO, fmt, __VA_ARGS__)

#define SYLAR_LOG_FMT_DEBUG(logger, fmt, ...) \
  SYLAR_LOG_FMT_LEVEL(logger, sylar::LogLevel::DEBUG, fmt, __VA_ARGS__)

// 日志级别
class LogLevel {
 public:
  enum level {
    /// 致命情况，系统不可用
    FATAL = 0,
    /// 高优先级情况，例如数据库系统崩溃
    ALERT = 100,
    /// 严重错误，例如硬盘错误
    CRIT = 200,
    /// 错误
    ERROR = 300,
    /// 警告
    WARN = 400,
    /// 正常但值得注意
    NOTICE = 500,
    /// 一般信息
    INFO = 600,
    /// 调试信息
    DEBUG = 700,
    /// 未设置
    NOTSET = 800,
  };
  static std::string LevelToString(LogLevel::level);

 private:
};

// 日志器
class Logger {
 public:
  using ptr = std::shared_ptr<Logger>;
  Logger(std::string&);
  void Log(LogEvent::ptr);

  void AddAppender(LogAppender::ptr appender);
  void DelAppender(LogAppender::ptr appender);

 private:
  std::string name_;
  std::vector<LogAppender::ptr> appenders_;
};

// 日志输出器
class LogAppender {
 public:
  using ptr = std::shared_ptr<LogAppender>;
  virtual ~LogAppender();
  virtual void Log(LogEvent::ptr) = 0;

  void SetFormatter(LogFormatter::ptr formatter) { formatter_ = formatter; }
  LogFormatter::ptr GetFormatter() { return formatter_; }

 protected:
  LogFormatter::ptr formatter_;
  LogFormatter::ptr default_formatter_;
};
// 日志输出地虚基类， 的 派生类
class StdoutLogAppender : public LogAppender {
 public:
  void Log(LogEvent::ptr event) override;
};

// 对日志的每一条项细分,做真正的写入
class FormatItem {
 public:
  using ptr = std::shared_ptr<FormatItem>;
  virtual void Format(std::ostream& os, LogEvent::ptr event) = 0;
};
// 日志格式器
class LogFormatter {
 public:
  using ptr = std::shared_ptr<LogFormatter>;
  LogFormatter(
      const std::string& pattern =
          "%d{%Y-%m-%d %H:%M:%S} [%rms]%T%t%T%N%T%F%T[%p]%T[%c]%T%f:%l%T%m%n")
      : pattern_(pattern) {}
  void Init();  // 解析pattern_,填充items
  void Format(std::ostream& os, LogEvent::ptr event);

 private:
  std::string pattern_;  // 日志格式模板字符串
  std::vector<FormatItem::ptr> items_;
};
class LineFormatItem : public FormatItem {
 public:
  void Format(std::ostream& os, LogEvent::ptr event) override;
};
class FileFormatItem : public FormatItem {
 public:
  void Format(std::ostream& os, LogEvent::ptr event) override;
};
// 更多FormatItem的派生类

// 日志事件的封装
class LogEvent {
 public:
  using ptr = std::shared_ptr<LogEvent>;

  LogEvent(int line, std::string& file, int pid, int thread_id,
           std::string& date_fmt)
      : line_(line),
        file_(file),
        pid_(pid),
        thread_id_(thread_id),
        date_fmt_(date_fmt) {}

  int GetLine() const { return line_; }
  std::string GetFile() const { return file_; }
  int GetPid() const { return pid_; }
  int GetThreadId() const { return thread_id_; }
  std::string GetDateFmt() const { return date_fmt_; }

 private:
  int line_;
  std::string file_;
  int pid_;
  int thread_id_;
  std::string date_fmt_;
};

// 对日志事件的进一步封装，内含Logger对象指针和LogEvent对象指针，
// 日志宏利用该类的析构函数触发日志写入
class LogEventWrapper {
 public:
  using ptr = std::shared_ptr<LogEventWrapper>;
  ~LogEventWrapper();

 private:
  Logger::ptr logger_;
  LogEvent::ptr event_;
};

class LoggerManager {
 public:
  LoggerManager();
  void Init();
  Logger::ptr GetLogger(const std::string& name) {
    auto it = loggers_.find(name);
    if (it != loggers_.end())
      return it->second;
    else
      return nullptr;
  }
  Logger::ptr GetRoot() const { return root_; }

 private:
  std::unordered_map<std::string, Logger::ptr> loggers_;
  Logger::ptr root_;
};